import _ from 'lodash';
import { UECanNotCopyChildProps, UECanNotCopyProps, UECanNotMoveChildProps, UECanNotMoveInProps, UECanNotMoveOutProps, UECanNotMoveProps, UECanNotRemoveChildProps, UECanNotRemoveProps, UECanNotSelectProps, UEHelper, UERender, UERenderItem, UETransfer, UETransferEditor, UETransferExtend, UETransferItem, UETransferEditorAttrs } from 'vue-uieditor';

const ivuedUseAttr = 'ivued-use-attr';
function getUieditorChild(children): UERenderItem {
  const find = _.find(children, function (item: UERenderItem) {
    if (!item || _.isString(item)) return false;
    return _.has(item?.props || {}, ivuedUseAttr);
  });
  return find;
}

const iconPre = 'ivu-icon ivu-icon-';

const baseModuleGroupOrder = 5;
const baseModuleGroup = 'iView 组件库/基础组件';

const formGroupOrder = 6;
const formGroup = 'iView 组件库/表单组件';

const navGroupOrder = 7;
const navGroup = 'iView 组件库/导航组件';

const layoutGroupOrder = 8;
const layoutGroup = 'iView 组件库/布局组件';

const viewGroupOrder = 9;
const viewGroup = 'iView 组件库/视图组件';

const _tableData = "[\n  {\n    name:'name',\n    age:'age',\n    address:'address'\n  }\n]";
const _tableCols = "[\n  {\n    title: 'Name',\n    key: 'name'\n  },\n  {\n    title: 'Age',\n    key: 'age'\n  },\n  {\n    title: 'Address',\n    key: 'address'\n  }\n]";
function _newTableAttrs() {
  return {
    'data': {
      desc: '数据，<a href="https://www.iviewui.com/components/table" target="_blank">配置项参考</a>',
      order: 0,
      value: _tableData,
      demoValue: _tableData,
      editorBind: true,
      bind: true,
      enabledBind: false
    },
    'columns': {
      desc: '列数据，<a href="https://www.iviewui.com/components/table" target="_blank">配置项参考</a>',
      order: 1,
      value: _tableCols,
      demoValue: _tableCols,
      editorBind: true,
      bind: true,
      enabledBind: false
    },
    'stripe': {
      desc: '是否显示间隔斑马纹',
      order: 2,
      type: 'boolean'
    },
    'border': {
      desc: '是否显示纵向边框',
      order: 3,
      type: 'boolean',
      effect: true
    },
    'show-header': {
      desc: '是否显示表头',
      order: 4,
      type: 'boolean',
      value: 'true',
      effect: true
    },
    'width': {
      desc: '表格宽度',
      order: 5,
      effect: true,
      type: 'number'
    },
    'height': {
      desc: '设置后，如果表格内容大于此值，会固定表头',
      order: 6,
      effect: true,
      type: 'number'
    },
    'max-height': {
      desc: '设置后，如果表格内容大于此值，会固定表头',
      order: 7,
      effect: true,
      type: 'number'
    },
    'loading': {
      desc: '表格是否加载中',
      order: 8,
      type: 'boolean',
      effect: true
    },
    'on-select': {
      desc: '选中事件，在多选模式下有效，选中某一项时触发',
      order: 9,
      event: true
    },
    'on-select-cancel': {
      desc: '取消选中事件，在多选模式下有效，取消选中某一项时触发',
      order: 10,
      event: true
    },
    'on-select-all': {
      desc: '取消全选事件，在多选模式下有效，点击全选时触发',
      order: 11,
      event: true
    },
    'on-select-all-cancel': {
      desc: '取消全选事件，在多选模式下有效，点击取消全选时触发',
      order: 12,
      event: true
    },
    'on-selection-change': {
      desc: '选中项事件，在多选模式下有效，只要选中项发生变化时就会触发',
      order: 13,
      event: true
    },
    'on-sort-change': {
      desc: '排序事件，排序时有效，当点击排序时触发',
      order: 14,
      event: true
    },
    'on-filter-change': {
      desc: '筛选事件，筛选时有效，筛选条件发生变化时触发',
      order: 15,
      event: true
    },
    'on-row-click': {
      desc: '单击某一行时触发',
      order: 16,
      event: true
    },
    'on-row-dblclick': {
      desc: '双击某一行时触发',
      order: 17,
      event: true
    }
  } as UETransferEditorAttrs;
}

function _newEditingTransfer(renderEx: UERenderItem): (render: UERenderItem, extend?: UETransferExtend) => UERenderItem {
  return function transfer(render, { editing }) {
    if (editing) {
      return _.merge({}, render, renderEx);
    } else
      return render;
  }
}

function _newMenuToolbar({ render, service }) {
  return [
    {
      title: "添加菜单",
      icon: "layui-icon layui-icon-addition",
      click() {
        service.addByJson({
          type: 'MenuItem'
        },
          render.editorId,
          "in"
        ).then(function () {
          service.setCurrent(render.editorId);
        });
      },
    },
    {
      title: "添加子菜单",
      icon: "layui-icon layui-icon-add-circle",
      click() {
        service.addByJson(
          {
            type: 'Submenu'
          },
          render.editorId,
          "in"
        ).then(function () {
          service.setCurrent(render.editorId);
        });

      },
    },
    {
      title: "添加分组",
      icon: "layui-icon layui-icon-add-circle",
      click() {
        service.addByJson(
          {
            type: 'MenuGroup'
          },
          render.editorId,
          "in"
        ).then(function () {
          service.setCurrent(render.editorId);
        });

      },
    }
  ];
}

function _newSubmenu(p: { title: string }, ext?: UETransferEditor): UETransferItem {
  const { title } = p;
  return {
    transfer(render, { editing }) {
      if (editing) {
        render.type = 'div';
      }
      return render;
    },
    "editor": _.assign({
      order: 0,
      groupOrder: navGroupOrder,
      group: navGroup,
      text: title,
      container: true,
      showInTree: false,
      toolbar({ render, service }) {
        return _newMenuToolbar({ render, service });
      },
      moving({ toEditor, type2 }) {
        return toEditor && (
          toEditor.name == 'MenuGroup' || toEditor.name == 'Submenu'
          || (toEditor.name == 'Menu' && type2 == 'in'));
      },
      transferAttr({ render, attrs, editing }) {
        if (editing) {
          if (_.size(render.children) == 0) {
            render.children = [];
            if (attrs.name) {
              attrs.name.value = UEHelper.makeAutoId();
              render.children.push({
                type: 'template',
                props: {
                  slot: 'title',
                  [UECanNotMoveProps]: true
                },
                children: [
                  {
                    type: 'Icon', props: {
                      type: 'ivu-icon-ios-people',
                      'class': 'mr-sm',
                      [UECanNotMoveProps]: true
                    }
                  }, {
                    "type": "uieditor-text",
                    "props": {
                      "text": title,
                      [UECanNotMoveProps]: true
                    }
                  }]
              });
            }
            render.children.push({
              type: 'MenuItem'
            });
          }
        }
      }
    } as UETransferEditor, ext)
  } as UETransferItem;
}

function _newFormItem() {
  return {
    type: 'Col',
    props: {
      [UECanNotMoveChildProps]: true,
      [UECanNotMoveInProps]: true,
      [UECanNotRemoveChildProps]: true,
      [UECanNotCopyChildProps]: true
    },
    children: [{
      type: 'FormItem',
      props: {}
    }]
  } as UERenderItem;
}

const _buttonJson = {
  type: 'Button',
  children: [{
    "type": "Icon",
    "props": {
      "class": "mr-sm",
      [UECanNotMoveProps]: true
    }
  }, {
    type: 'uieditor-text',
    "props": {
      [UECanNotMoveProps]: true
    }
  }]
} as UERenderItem;

export const IViewTransfer: UETransfer = UERender.DefineTransfer({
  Button: {
    "editor": {
      text: 'Button 按钮',
      order: 0,
      groupOrder: baseModuleGroupOrder,
      group: baseModuleGroup,
      inline: true,
      container: true,
      icon: iconPre + 'logo-youtube',
      json: _buttonJson,
      attrs: {
        type: {
          effect: true,
          type: 'select',
          order: 1,
          datas: ["primary", "info", "success", "warning", "error", "dashed", "text"]
        },
        shape: {
          effect: true,
          type: 'select',
          order: 2,
          datas: ['circle']
        },
        size: {
          effect: true,
          type: 'select',
          order: 2,
          datas: ['large', 'small', 'default']
        },
        class: { value: 'mr-sm' },
        loading: {
          bind: true,
          type: 'boolean',
          order: 4
        },
        click: { event: true, order: 30 }
      }
    }
  },
  Row: {
    "editor": {
      text: 'Row 栅格行',
      order: 1,
      groupOrder: layoutGroupOrder,
      group: layoutGroup,
      icon: iconPre + 'ios-menu',
      container: true,
      containerBorder: false,
      json: {
        children: [{ type: 'Col' }]
      },
      attrs: {
        'gutter': {
          desc: '栅格间距，单位 px，左右平分',
          order: 0,
          type: 'number',
          value: 16,
          effect: true
        },
        'type': {
          desc: '布局模式',
          type: 'select',
          datas: ['flex'],
          effect: true
        },
        'align': {
          desc: '垂直对齐方式-flex模式',
          order: 0,
          type: 'select-only',
          datas: ['top', 'middle', 'bottom'],
          effect: true
        },
        'justify': {
          desc: '水平排列方式-flex模式',
          order: 0,
          type: 'select-only',
          datas: ['start', 'end', 'center', 'space-around', 'space-between'],
          effect: true
        },
        'class-name': {
          desc: "自定义的class名称",
          order: 0,
          effect: true

        }
      }
    }
  },
  Col: {
    "editor": {
      text: 'Col',
      order: 2,
      groupOrder: layoutGroupOrder,
      group: layoutGroup,
      showInTree: false,
      container: true,
      attrs: {
        'span': {
          desc: '占位格数',
          order: 0,
          type: 'slider',
          typeOption: { min: 1, max: 24 },
          value: 24,
          effect: true
        },
        'order': {
          desc: '栅格顺序-flex模式',
          order: 0,
          type: 'number',
          effect: true,
          bind: false,
        },
        'offset': {
          desc: '栅格左侧间隔格数',
          order: 0,
          type: 'slider',
          typeOption: { min: 0, max: 24 },
          effect: true
        },
        'push': {
          desc: '栅格向右移动格数',
          order: 0,
          type: 'slider',
          typeOption: { min: 0, max: 24 },
          effect: true
        },
        'pull': {
          desc: '栅格向左移动格数',
          order: 0,
          type: 'slider',
          typeOption: { min: 0, max: 24 },
          effect: true
        }
      }
    }
  },
  Form: {
    "editor": {
      text: 'Form 表单',
      order: 3,
      groupOrder: formGroupOrder,
      group: formGroup,
      icon: iconPre + 'ios-list-box-outline',
      container: true,
      toolbar({ render, service }) {
        const child = _.first(render.children) as UERenderItem;
        if (!child) return [];
        return [
          {
            title: "添加表单项",
            icon: "layui-icon layui-icon-addition",
            click() {
              const id = child.editorId
              service.addByJson(
                _newFormItem(),
                id,
                "in"
              ).then(function () {
                service.setCurrent(render.editorId);
              });
            },
          },
        ];
      },
      json: {
        children: [{
          type: 'Row',
          props: {
            [UECanNotSelectProps]: true,
            [UECanNotRemoveProps]: true,
            [UECanNotMoveProps]: true,
            [UECanNotSelectProps]: true,
            [UECanNotMoveInProps]: true,
            [UECanNotMoveOutProps]: true
          },
          children: [_newFormItem()]
        }]
      },
      attrs: {
        'class': { value: 'pt-lg' },
        'label-width': {
          order: 0,
          bind: true,
          editorBind: true,
          value: '120'
        },
        inline: {
          order: 1,
          type: 'boolean'
        },
        'label-position': {
          order: 1,
          type: 'select',
          datas: ['left', 'right', 'top']
        }
      }
    }
  },
  FormItem: {
    "editor": {
      text({ attrs }) {
        const label = attrs.label.value;
        const prop = attrs.prop.value;
        return !prop ? label : `${label}（${prop}）`;
      },
      defaultText: 'FormItem',
      order: 4,
      group: formGroup,
      icon: iconPre + 'ios-reorder',
      container: true,
      containerBorder: false,
      showInTree: false,
      attrs: {
        label: { order: 1, effect: true, value: "formitem：" },
        'prop,label-width': { order: 2 }
      }
    }
  },
  Card: {
    "editor": {
      text: '%title%',
      defaultText: 'Card 卡片',
      order: 5,
      groupOrder: layoutGroupOrder,
      group: layoutGroup,
      icon: iconPre + 'ios-card',
      container: true,
      controlLeft: false,
      containerBorder: false,
      toolbar({ render, service }) {
        return [
          {
            title: "添加 title",
            icon: "layui-icon layui-icon-addition",
            click() {
              service.addByJson({
                type: 'template',
                props: { slot: 'title' }
              },
                render.editorId,
                "in"
              ).then(function () {
                service.setCurrent(render.editorId);
              });

            },
          },
          {
            title: "添加 extra",
            icon: "layui-icon layui-icon-add-circle",
            click() {
              service.addByJson(
                {
                  type: 'template',
                  props: { slot: 'extra' }
                },
                render.editorId,
                "in"
              ).then(function () {
                service.setCurrent(render.editorId);
              });

            },
          }
        ];
      },
      attrs: {
        'title': {
          text: '标题',
          order: 0,
          value: 'Card 卡片',
          effect: true
        },
        'icon': {
          text: '标题前的图标',
          order: 0,
          effect: false
        },
        'padding': {
          desc: '单位px',
          text: 'padding',
          order: 0,
          effect: true
        },
        'bordered': {
          text: '是否显示边框',
          order: 0,
          type: 'boolean-only',
          effect: true
        },
        'dis-hover': {
          text: '禁用鼠标悬停',
          order: 0,
          type: 'boolean-only',
          effect: true
        },
        'shadow': {
          text: '是否隐藏阴影',
          order: 0,
          type: 'boolean-only',
          effect: true
        },
        class: { value: 'mb-sm' }
      }
    }
  },
  Tabs: {
    "editor": {
      order: 6,
      groupOrder: layoutGroupOrder,
      group: layoutGroup,
      text: 'Tabs 标签页',
      icon: iconPre + 'ios-folder-outline',
      container: true,
      controlLeft: false,
      json: {
        props: {
          [UECanNotMoveInProps]: true,
          [UECanNotMoveOutProps]: true,
          [UECanNotRemoveChildProps]: true,
          [UECanNotMoveChildProps]: true
        }
      },
      toolbar({ render, service }) {
        return [
          {
            title: "添加",
            icon: "layui-icon layui-icon-addition",
            click() {
              const name = "tab" + UEHelper.makeAutoId();
              service.setRenderTemp(render.editorId, 'tabs_cur', name);
              service.addByJson(
                { "type": "TabPane", "props": { "name": name, "label": `Tab${_.size(render.children) + 1}` } },
                render.editorId,
                "in"
              ).then(function () {
                service.setCurrent(render.editorId);
              });

            },
          },
        ];
      },
      attrs: {
        type: {
          order: 1,
          type: 'select',
          datas: ['line', 'card'],
          effect: true
        },
        animated: {
          order: 2,
          type: 'boolean',
          bind: true,
        },
        name: {
          order: 3,
          effect: true
        },
        'on-click,on-tab-remove': { event: true, order: 30 }
      },
      transferAttr({ render, service, editing }) {
        //必须保留一个TabPane
        if (!render.children || render.children.length == 0) {
          render.children = [{ type: 'TabPane' }];
        }

        const props = render.props;
        if (editing) {
          //编辑时，保留当前tab页
          const id = render.editorId;
          const temp = service.getRenderTemp(id, 'tabs_cur');
          props['value'] = temp;
          props[':animated'] = 'false';
          props['@on-click'] = `$service.setRenderTemp('${id}', 'tabs_cur', $event)`;

          //同步 tab name属性 到 tabPane tab属性
          const name = render.attrs?.name.value || '';
          _.forEach(render.children, function (item: UERenderItem) {
            if (item.attrs)
              item.attrs.tab.value = name;
            else if (item.props)
              item.props.tab = name;
          });
        } else {
          delete props['value'];
          delete props[':animated'];
          delete props['@on-click'];
        }

      }
    }
  },
  TabPane: {
    "editor": {
      text: 'TabPane：%label%',
      order: 7,
      showInTree: false,
      container: true,
      coping({ render, parent, service }) {
        const name = "tab" + UEHelper.makeAutoId();
        let pId = parent?.editorId;
        service.setRenderTemp(pId, 'tabs_cur', name);
        render.props = _.assign({}, render.props, {
          name
        });
        return true;
      },
      attrs: {
        'label:Tab1,name:tab1,tab,icon': {
          order: 1,
          effect: true
        },
        tab: { order: 10, effect: true, show: false }
      }
    }
  },
  Input: {
    "editor": {
      text: 'Input 输入框',
      order: 8,
      groupOrder: formGroupOrder,
      group: formGroup,
      base: true,
      icon: iconPre + 'ios-create-outline',
      placeholderAttr: true,
      disabledAttr: true,
      attrs: {
        type: {
          effect: true,
          type: 'select',
          order: 1,
          value: "text",
          datas: ["text", "password", "textarea", "number", "url", "email", "date", "tel"]
        },
        icon: {
          text: '输入框尾部的图标',
          effect: true,
          order: 2
        },
        prefix: {
          effect: true,
          order: 3,
          desc: '前置图标'
        },
        'search,clearable,autosize,number,autocomplete,autofocus': {
          order: 5,
          type: 'boolean'
        },
        rows: {
          effect: true,
          order: 10,
          type: 'number'
        },
        'on-click,on-search,on-enter,on-change,on-focus,on-blur,on-keyup,on-keydown,on-keypress,on-clear': {
          order: 30,
          event: true
        }
      }
    }
  },
  InputNumber: {
    "editor": {
      text: 'InputNumber 数字输入框',
      order: 9,
      groupOrder: formGroupOrder,
      group: formGroup,
      base: true,
      icon: iconPre + 'ios-create-outline',
      placeholderAttr: true,
      disabledAttr: true,
      attrs: {
        'max': {
          text: '最大值',
          order: 0,
          effect: true,
          bind: false
        },
        'min': {
          text: '最小值',
          order: 0,
          effect: true,
          bind: false
        },
        'step': {
          text: '每次改变的步伐',
          order: 0,
          effect: true,
          bind: false
        },
        'size': {
          text: '输入框尺寸',
          order: 4,
          type: 'select',
          value: 'default',
          datas: ["default", "small", "large"],
          effect: true
        },
        'disabled': {
          text: '设置禁用状态',
          order: 2,
          type: 'boolean'
        },
        'placeholder': {
          text: '占位文本',
          order: 0
        },
        "formatter": {
          text: '指定输入框展示值的格式',
          order: 5,
          event: true
        },
        'parser': {
          desc: '指定从 formatter 里转换回数字的方式，和 formatter 搭配使用',
          text: '配合formatter使用',
          order: 5,
          event: true
        },
        'readonly': {
          text: '是否设置为只读',
          order: 2,
          type: 'boolean'
        },
        'editable': {
          text: '是否可编辑',
          order: 2,
          type: 'boolean'
        },
        'precision': {
          text: '数值精度',
          order: 2
        },
        'element-id': {
          text: '给表单元素设置 id，详见 Form 用法。',
          order: 3,
          enabledBind: false
        },
        'active-change': {
          desc: '是否实时响应数据，设置为 false 时，只会在失焦时更改数据',
          order: 3,
          type: "boolean"
        },
        'on-change,on-focus,on-blur': {
          desc: '数值改变时的回调',
          order: 5,
          event: true
        }
      }
    }
  },
  Select: {
    transfer: _newEditingTransfer({ type: 'div' }),
    "editor": {
      text: 'Select 选择器',
      order: 10,
      groupOrder: formGroupOrder,
      group: formGroup,
      icon: iconPre + 'ios-arrow-down',
      placeholderAttr: true,
      disabledAttr: true,
      container: true,
      transferAttr({ render, editing }) {
        if (editing) {
          if (_.size(render.children) == 0) {
            render.children = [{
              type: 'Option',
              props: {
                label: '选项1',
                value: '1'
              }
            }];
          }
        }
      },
      attrs: {
        multiple: {
          type: 'boolean',
          order: 1
        },
        'filterable,clearable,filter-by-label,label-in-value,transfer,capture,allow-create': {
          type: 'boolean-only',
          order: 2
        },
        'loading': {
          type: 'boolean',
          order: 10
        },
        'loading-text,not-found-text,prefix,max-tag-placeholder': {
          order: 12,
        },
        'max-tag-count': {
          type: 'number', order: 20
        },
        size: {
          type: 'select',
          order: 23,
          effect: true,
          datas: ['large', 'small', 'default']
        },
        placement: {
          type: 'select',
          order: 24,
          effect: true,
          datas: ['top', 'bottom', 'top-start', 'bottom-start', 'top-end', 'bottom-end']
        },
        'remote-method': {
          bind: true, enabledBind: false,
          order: 25
        },
        'on-change,on-query-change,on-clear,on-open-change,on-create,on-select': { event: true, order: 31 }
      }
    }
  },
  Option: {
    transfer: _newEditingTransfer({ type: 'Select' }),
    "editor": {
      text: 'Option',
      order: 11,
      icon: iconPre + 'ios-arrow-down',
      showInTree: false,
      disabledAttr: true,
      draggable: false,
      attrs: {
        'value,label': {
          order: 0, row: true
        }
      }
    }
  },
  Checkbox: {
    "editor": {
      order: 12,
      groupOrder: formGroupOrder,
      group: formGroup,
      text: 'Checkbox 多选框',
      inline: true,
      icon: iconPre + 'ios-checkbox-outline',
      disabledAttr: true,
      moving({ fromRender, service }) {
        if (!fromRender) return true;
        const find = service.closest(fromRender, function (item) { return item.type == 'CheckboxGroup' });
        return !find;
      },
      transferAttr({ render, attrs, editing }) {
        const { text } = attrs;
        if (_.size(render.children) == 0) render.children = [];
        const { value, bind } = text;
        const child = {
          type: "span",
          props: {
            [ivuedUseAttr]: true
          },
          children: [
            editing ? value : (bind ? `{{${value}}}` : value)
          ]
        };
        const ueChild = getUieditorChild(render.children);
        if (ueChild)
          UEHelper.assignDepth(ueChild, child);
        else
          render.children.push(child);
      },
      attrs: {
        text: {
          effect: true,
          value: "Checkbox",
          editorOlny: true,
          order: 0
        },
        'label:1,true-value,false-value': { order: 1 },
        size: {
          type: 'select',
          datas: ['large', 'small', 'default'],
          effect: true,
          order: 6
        },
        'on-change': { event: true, order: 30 }
      }
    }
  },
  CheckboxGroup: {
    "editor": {
      order: 13,
      groupOrder: formGroupOrder,
      group: formGroup,
      text: 'CheckboxGroup 多选框组',
      inline: true,
      container: true,
      icon: iconPre + 'md-checkbox',
      disabledAttr: true,
      transferAttr({ render, attrs, editing }) {
        if (editing) {
          if (_.size(render.children) == 0) {
            render.children = [{
              type: 'Checkbox',
              props: {
                label: '1',
                text: 'Checkbox'
              }
            }];
          }
        }
      },
      attrs: {
        size: {
          type: 'select',
          datas: ['large', 'small', 'default'],
          effect: true,
          order: 6
        },
        'on-change': { event: true, order: 30 }
      }
    }
  },
  RadioGroup: {
    "editor": {
      text: 'RadioGroup 单选框组',
      order: 14,
      groupOrder: formGroupOrder,
      group: formGroup,
      inline: true,
      icon: iconPre + 'ios-radio-button-on',
      container: true,
      disabledAttr: true,
      transferAttr({ render, attrs, editing }) {
        if (editing) {
          if (_.size(render.children) == 0) {
            render.children = [{
              type: 'Radio',
              props: {
                label: '1',
                text: 'Radio1'
              }
            }];
          }
        }
      },
      attrs: {
        type: {
          type: 'select',
          datas: ['button'],
          effect: true,
          order: 1
        },
        vertical: {
          type: 'boolean',
          order: 2
        },
        size: {
          type: 'select',
          datas: ['large', 'small', 'default'],
          effect: true,
          order: 3
        },
        'on-change': { event: true, order: 30 }
      }
    }
  },
  Radio: {
    "editor": {
      order: 15,
      groupOrder: formGroupOrder,
      group: formGroup,
      text: 'Radio 单选框',
      inline: true,
      icon: iconPre + 'ios-radio-outline',
      showInTree: false,
      disabledAttr: true,
      moving({ fromRender, service }) {
        if (!fromRender) return true;
        const find = service.closest(fromRender, function (item) { return item.type == 'RadioGroup' });
        return !find;
      },
      transferAttr({ render, attrs, editing }) {
        const { text } = attrs;
        if (_.size(render.children) == 0) render.children = [];
        const { value, bind } = text;
        const child = {
          type: "span",
          props: {
            [ivuedUseAttr]: true
          },
          children: [
            editing ? value : (bind ? `{{${value}}}` : value)
          ]
        };
        const ueChild = getUieditorChild(render.children);
        if (ueChild)
          UEHelper.assignDepth(ueChild, child);
        else
          render.children.push(child);
      },
      attrs: {
        text: {
          effect: true,
          value: "Radio",
          editorOlny: true,
          order: 0
        },
        'label:1,true-value,false-value': { order: 1 },
        size: {
          type: 'select',
          datas: ['large', 'small', 'default'],
          effect: true,
          order: 6
        },
        'on-change': { event: true, order: 30 }
      }
    }
  },
  'i-switch': {
    "editor": {
      order: 16,
      groupOrder: formGroupOrder,
      group: formGroup,
      text: "Switch 开关",
      inline: true,
      icon: iconPre + 'ios-switch',
      attrs: {
        'true-value,false-value': { order: 0 },
        size: {
          effect: true,
          order: 3,
          type: 'select',
          datas: ["large", "small"]
        },
        'on-change': { event: true, order: 30 }
      }
    },
  },
  ColorPicker: {
    type: 'ColorPicker',
    "editor": {
      text: 'ColorPicker 颜色选择器',
      order: 17,
      groupOrder: formGroupOrder,
      group: formGroup,
      base: true,
      icon: iconPre + 'ios-color-palette',
      disabledAttr: true,
      inline: true,
      attrs: {
        'editable,alpha,hue,recommend': {
          bind: true,
          type: 'boolean'
        },
        'colors,format,size': {
          order: 5
        },
        'value': { value: '#19be6b', editorOlny: true, effect: true, show: false },
        'on-change,on-active-change,on-open-change': {
          order: 30,
          event: true
        }
      }
    }
  },
  Tag: {
    "editor": {
      order: 18,
      groupOrder: viewGroupOrder,
      group: viewGroup,
      container: true,
      text: 'Tag 标签',
      icon: iconPre + 'md-pricetag',
      disabledAttr: true,
      inline: true,
      transferAttr({ render }) {
        if (_.size(render.children) == 0) {
          render.children = [{
            "type": "uieditor-text",
            "props": {
              "text": "文本内容"
            }
          }];
        }
      },
      attrs: {
        text: {
          effect: true,
          value: "标签",
          order: 0
        },
        name: {
          order: 1
        },
        type: {
          effect: true,
          order: 2,
          type: 'select',
          value: 'dot',
          datas: ['border', 'dot']
        },
        color: {
          effect: true,
          order: 3,
          type: 'select',
          datas: ['default', 'primary', 'success', 'warning', 'error', 'blue', 'green', 'red', 'yellow', 'pink', 'magenta', 'volcano', 'orange', 'gold', 'lime', 'cyan', 'geekblue', 'purple']
        },
        'closable,checkable,checked,fade': {
          order: 4,
          type: 'boolean'
        },
        'on-change,on-close': {
          order: 30,
          event: true
        }
      }
    }
  },
  'i-circle': {
    "editor": {
      order: 19,
      groupOrder: viewGroupOrder,
      group: viewGroup,
      container: true,
      text: 'Circle 进度环',
      icon: iconPre + 'ios-radio-button-off',
      disabledAttr: true,
      inline: true,
      attrs: {
        percent: {
          effect: true,
          order: 0,
          value: '50',
          type: 'number'
        },
        'size,stroke-linecap,stroke-width,stroke-color,trail-width,trail-color': {
          order: 1
        },
        dashboard: {
          order: 10,
          type: 'boolean'
        }
      }
    }
  },
  AutoComplete: {
    "editor": {
      order: 20,
      groupOrder: formGroupOrder,
      group: formGroup,
      text: 'AutoComplete 自动完成',
      base: true,
      icon: iconPre + 'ios-arrow-down',
      placeholderAttr: true,
      disabledAttr: true,
      attrs: {
        data: {
          order: 0,
          bind: true,
          enabledBind: false,
          value: "['选项1']",
          desc: "数据，格式：<br /> ['选项1', '选项2']"
        },
        icon: {
          effect: true,
          order: 1
        },
        'filter-method': {
          order: 2,
          bind: true
        },
        placement: {
          order: 3,
          type: 'select',
          datas: ['top', 'bottom']
        },
        'clearable,transfer': {
          order: 4,
          type: 'boolean'
        },
        'on-search,on-change,on-select,on-focus,on-blur,on-clear': {
          order: 30,
          event: true
        }
      }
    }
  },
  DatePicker: {
    "editor": {
      text: 'DatePicker 日期选择器',
      order: 21,
      groupOrder: formGroupOrder,
      group: formGroup,
      icon: iconPre + 'ios-calendar-outline',
      placeholderAttr: true,
      disabledAttr: true,
      attrs: {
        style: {
          value: 'width:100%'
        },
        type: {
          type: 'select',
          order: 1,
          value: "date",
          datas: ["date", "daterange", "datetime", "datetimerange", "year", "month"]
        },
        format: {
          order: 2
        },
        multiple: {
          order: 5,
          type: 'boolean'
        },
        'on-change,on-open-change,on-ok,on-clear,on-clickoutside': {
          order: 30,
          event: true
        }
      }
    }
  },
  TimePicker: {
    "editor": {
      text: 'TimePicker 时间选择器',
      order: 22,
      groupOrder: formGroupOrder,
      group: formGroup,
      icon: iconPre + 'ios-time-outline',
      placeholderAttr: true,
      disabledAttr: true,
      attrs: {
        style: {
          value: 'width:100%'
        },
        type: {
          type: 'select',
          order: 1,
          value: "time",
          datas: ["time", "timerange"]
        },
        format: {
          order: 2
        },
        'on-change,on-open-change,on-ok,on-clear': {
          order: 30,
          event: true
        }
      }
    }
  },
  Divider: {
    "editor": {
      order: 23,
      groupOrder: layoutGroupOrder,
      group: layoutGroup,
      text: 'Divider 分割线',
      icon: iconPre + 'ios-more',
      transferAttr({ render, attrs, editing }) {
        const { text } = attrs;
        if (_.size(render.children) == 0) render.children = [];
        const { value, bind } = text;
        const child = {
          type: "span",
          props: {
            [ivuedUseAttr]: true
          },
          children: [
            editing ? value : (bind ? `{{${value}}}` : value)
          ]
        };
        const ueChild = getUieditorChild(render.children);
        if (ueChild)
          UEHelper.assignDepth(ueChild, child);
        else
          render.children.push(child);
      },
      attrs: {
        text: {
          effect: true,
          value: "分割线",
          editorOlny: true,
          order: 0
        },
        type: {
          effect: true,
          order: 1,
          type: 'select',
          datas: ["horizontal", "vertical"]
        },
        orientation: {
          effect: true,
          order: 2,
          type: 'select',
          datas: ["left", "right", "center"]
        },
        dashed: {
          effect: true,
          order: 3,
          type: 'boolean'
        }
      }
    }
  },
  Dropdown: {
    transfer: _newEditingTransfer({ type: 'div' }),
    "editor": {
      order: 24,
      groupOrder: navGroupOrder,
      group: navGroup,
      text: 'Dropdown 下拉菜单',
      container: true,
      inline: true,
      icon: iconPre + 'md-arrow-dropdown',
      transferAttr({ render, editing }) {
        if (editing) {
          if (_.size(render.children) == 0) {
            render.props = {
              ...(render.props || {}),
              [UECanNotMoveChildProps]: true,
              [UECanNotCopyChildProps]: true
            };
            render.children = [_.merge({
              "type": "Button",
              "props": {
                "class": "mr-sm"
              }
            }, _buttonJson), {
              type: 'DropdownMenu'
            }];
          }
        }
      },
      attrs: {
        placement: {
          value: "bottom",
          order: 1,
          type: 'select',
          datas: _.map(['top', 'bottom', 'left', 'right'], function (item) {
            return _.map(['', 'start', 'end'], function (alain) {
              let val = alain ? [item, alain].join('-') : item;
              return val;
            }).join(',');
          }).join(',').split(',')
        },
        'stop-propagation,transfer:true,visible': {
          order: 8,
          type: 'boolean',
          bind: true
        },
        'transfer-class-name': { order: 8 },
        trigger: {
          value: "click",
          order: 7,
          type: 'select',
          datas: ['hover', 'click', 'contextMenu', 'custom']
        },
        'class': { value: 'mr-sm' },
        'on-select,on-open-change,on-clickoutside': { event: true, order: 30 }
      }
    }
  },
  DropdownMenu: {
    transfer: _newEditingTransfer({ type: 'div' }),
    "editor": {
      order: 25,
      groupOrder: navGroupOrder,
      group: navGroup,
      text: 'DropdownMenu',
      container: true,
      showInTree: false,
      moving({ toEditor, type2 }) {
        return toEditor &&
          (toEditor.name == 'DropdownMenu' ||
            (toEditor.name == 'Dropdown' && type2 == 'in')
            || (toEditor.name == 'DropdownItem' && type2 != 'in'));
      },
      toolbar({ render, service }) {
        return [
          {
            title: "添加菜单",
            icon: "layui-icon layui-icon-addition",
            click() {
              service.addByJson({
                type: 'DropdownItem'
              },
                render.editorId,
                "in"
              ).then(function () {
                service.setCurrent(render.editorId);
              });

            },
          },
          {
            title: "添加子菜单",
            icon: "layui-icon layui-icon-add-circle",
            click() {
              service.addByJson(
                {
                  "type": "Dropdown",
                  "props": {
                    "placement": "right-start",
                    ":transfer": "true",
                    "trigger": "hover"
                  },
                  "children": [
                    {
                      "type": "DropdownItem",
                      props: {
                        [UECanNotMoveProps]: true,
                        [UECanNotRemoveProps]: true,
                        [UECanNotCopyProps]: true
                      },
                      children: [
                        { type: 'Icon', props: { type: 'md-heart-outline', 'class': 'mr-sm' } },
                        {
                          "type": "uieditor-text",
                          "props": {
                            "text": "DropdownItem"
                          }
                        },
                        { type: 'Icon', props: { type: 'ios-arrow-forward', 'class': 'ml-sm' } }
                      ]
                    },
                    {
                      "type": "DropdownMenu",
                      props: {
                        [UECanNotMoveProps]: true,
                        [UECanNotRemoveProps]: true,
                        [UECanNotCopyProps]: true
                      },
                      "children": [
                        {
                          "type": "DropdownItem"
                        }
                      ]
                    }
                  ]
                },
                render.editorId,
                "in"
              ).then(function () {
                service.setCurrent(render.editorId);
              });
            },
          }
        ];
      },
      transferAttr({ render, editing }) {
        if (editing) {
          if (_.size(render.children) == 0) {
            render.children = [{
              type: 'DropdownItem'
            }];
          }
        }
      },
      attrs: {
        slot: { value: 'list', show: false }
      }
    }
  },
  DropdownItem: {
    transfer: _newEditingTransfer({ type: 'div' }),
    "editor": {
      order: 26,
      groupOrder: navGroupOrder,
      group: navGroup,
      text: 'DropdownItem',
      container: true,
      showInTree: false,
      moving({ toEditor, type2 }) {
        return toEditor && (toEditor.name == 'DropdownItem' || (toEditor.name == 'DropdownMenu' && type2 == 'in') || (toEditor.name == 'Dropdown' && type2 != 'in'));
      },
      transferAttr({ render, attrs, editing }) {
        const { text, icon } = attrs;
        if (_.size(render.children) == 0) render.children = [
          {
            type: 'Icon', props: {
              type: 'md-heart-outline',
              'class': 'mr-sm',
              [UECanNotMoveProps]: true
            }
          }, {
            "type": "uieditor-text",
            "props": {
              "text": "DropdownItem",
              [UECanNotMoveProps]: true
            }
          }];
      },
      attrs: {
        'divided,selected,disabled': {
          order: 8,
          type: 'boolean',
          bind: true
        },
        'click.native': { event: true, order: 30 }
      }
    }
  },
  Menu: {
    transfer: _newEditingTransfer({ type: 'div' }),
    "editor": {
      order: 27,
      groupOrder: navGroupOrder,
      group: navGroup,
      text: 'Menu 导航菜单',
      container: true,
      inline: true,
      icon: iconPre + 'ios-menu',
      toolbar({ render, service }) {
        return _newMenuToolbar({ render, service });
      },
      transferAttr({ render, attrs, editing }) {
        if (editing) {
          if (_.size(render.children) == 0) {
            render.children = [{
              type: 'MenuItem'
            }];
          }
        }
      },
      attrs: {
        mode: {
          order: 1,
          type: 'select',
          datas: ['horizontal', 'vertical']
        },
        theme: {
          order: 2,
          type: 'select',
          datas: ['light', 'dark', 'primary']
        },
        'active-name,open-names,width:240px': { order: 3 },
        accordion: {
          order: 6,
          type: 'boolean',
          bind: true
        },
        'on-select,on-open-change': { event: true, order: 30 }
      }
    }
  },
  Submenu: _newSubmenu({ title: 'Submenu' }, {
    order: 28,
    coping({ render }) {
      render.props = _.assign(render.props, {
        name: UEHelper.makeAutoId()
      });
      return true;
    },
    attrs: {
      name: { order: 1 }
    }
  }),
  MenuGroup: _newSubmenu({ title: 'MenuGroup' }, {
    order: 29,
    attrs: {
      title: { order: 1, value: 'MenuGroup' }
    }
  }),
  MenuItem: {
    transfer: _newEditingTransfer({ type: 'div' }),
    "editor": {
      order: 30,
      groupOrder: navGroupOrder,
      group: navGroup,
      text: 'MenuItem',
      container: true,
      showInTree: false,
      coping({ render }) {
        render.props = _.assign(render.props, {
          name: UEHelper.makeAutoId()
        });
        return true;
      },
      moving({ toEditor, type2 }) {
        return toEditor && (
          toEditor.name == 'MenuGroup' || toEditor.name == 'Submenu'
          || (toEditor.name == 'Menu' && type2 == 'in'));
      },
      transferAttr({ render, attrs, editing }) {
        if (_.size(render.children) == 0) {
          attrs.name.value = UEHelper.makeAutoId();
          render.children = [
            {
              type: 'Icon', props: {
                type: 'md-heart-outline',
                'class': 'mr-sm',
                [UECanNotMoveProps]: true
              }
            }, {
              "type": "uieditor-text",
              "props": {
                "text": "MenuItem",
                [UECanNotMoveProps]: true
              }
            }];
        }
      },
      attrs: {
        'name,to,target:_self': {
          order: 1
        },
        'replace,append': {
          order: 8,
          type: 'boolean',
          bind: true
        },
        'click.native': { event: true, order: 30 }
      }
    }
  },
  Alert: {
    "editor": {
      text: 'Alert 警告提示',
      order: 31,
      groupOrder: viewGroupOrder,
      group: viewGroup,
      container: true,
      icon: iconPre + 'ios-information-circle-outline',
      attrs: {
        type: {
          effect: true,
          value: "info",
          order: 0,
          type: 'select',
          datas: ["info", "success", "warning", "error"]
        },
        'show-icon, closable': {
          bind: true,
          order: 1,
          type: 'boolean'
        },
        'on-close': {
          order: 30,
          event: true
        }
      }
    }
  },
  Icon: {
    "editor": {
      order: 32,
      groupOrder: baseModuleGroupOrder,
      group: baseModuleGroup,
      text: 'Icon 图标',
      icon: iconPre + 'ios-heart-outline',
      inline: true,
      attrs: {
        'type:ios-heart-outline,size,color': {
          effect: true,
          groupOrder: 1,
          order: 1
        }
      }
    }
  },
  Slider: {
    "editor": {
      text: 'Slider 滑块',
      order: 33,
      groupOrder: formGroupOrder,
      group: formGroup,
      icon: iconPre + 'md-remove',
      disabledAttr: true,
      attrs: {
        'min,max,step,tip-format': {
          groupOrder: 1,
          order: 0
        },
        'range,show-input,show-stops,active-change ': {
          type: 'boolean',
          order: 5,
        },
        'show-tip': {
          type: 'select',
          order: 5,
          datas: ['hover', 'always', 'never']
        },
        'input-size': {
          type: 'select',
          order: 5,
          datas: ['large', 'small', 'default']
        },
        'on-change,on-input': {
          order: 30,
          event: true
        }
      }
    }
  },
  Tooltip: {
    transfer: _newEditingTransfer({ type: 'span' }),
    "editor": {
      text: 'Tooltip 文字提示',
      order: 34,
      groupOrder: viewGroupOrder,
      group: viewGroup,
      container: true,
      icon: iconPre + 'md-text',
      inline: true,
      disabledAttr: true,
      attrs: {
        content: {
          order: 0,
          value: 'Tooltip'
        },
        placement: {
          value: "top",
          order: 1,
          type: 'select',
          datas: _.map(['top', 'bottom', 'left', 'right'], function (item) {
            return _.map(['', 'start', 'end'], function (alain) {
              let val = alain ? [item, alain].join('-') : item;
              return val;
            }).join(',');
          }).join(',').split(',')
        },
        theme: {
          order: 2,
          type: 'select',
          datas: ['dark', 'light']
        },
        'delay,max-width,offset': {
          order: 3,
        },
        transfer: {
          order: 8,
          type: 'boolean'
        },
        'on-popper-show,on-popper-hide': {
          order: 30,
          event: true
        }
      }
    }
  },
  Poptip: {
    transfer: _newEditingTransfer({ type: 'div' }),
    "editor": {
      text: 'Poptip 气泡提示',
      order: 35,
      groupOrder: viewGroupOrder,
      group: viewGroup,
      container: true,
      icon: iconPre + 'ios-chatboxes-outline',
      disabledAttr: true,
      attrs: {
        content: {
          order: 0,
          value: 'Poptip'
        },
        'title,width,ok-text,cancel-text': {
          order: 1
        },
        placement: {
          value: "top",
          order: 8,
          type: 'select',
          datas: _.map(['top', 'bottom', 'left', 'right'], function (item) {
            return _.map(['', 'start', 'end'], function (alain) {
              let val = alain ? [item, alain].join('-') : item;
              return val;
            }).join(',');
          }).join(',').split(',')
        },
        trigger: {
          type: 'select',
          order: 9,
          datas: ["click", "focus"]
        },
        'transfer,confirm': {
          order: 10,
          type: 'boolean'
        },
        'on-popper-show,on-popper-hide,on-ok,on-cancel': {
          order: 30,
          event: true
        }
      }
    }
  },
  Steps: {
    "editor": {
      text: 'Steps 步骤条',
      order: 36,
      groupOrder: navGroupOrder,
      group: navGroup,
      icon: iconPre + 'ios-checkmark-circle-outline',
      container: true,
      containerBorder: false,
      controlLeft: false,
      transferAttr({ render }) {
        if (_.size(render.children) == 0) {
          render.children = [{
            type: 'Step'
          }];
        }
      },
      attrs: {
        current: {
          order: 0
        },
        status: {
          order: 1,
          type: 'select',
          value: "process",
          datas: ["wait", "process", "finish", "error"]
        },
        size: {
          order: 1,
          type: 'select',
          datas: ['small']
        },
        direction: {
          order: 1,
          type: 'select',
          value: 'horizontal',
          datas: ["horizontal", "vertical"]
        },
        'titleName:title,descName:desc': {
          order: 5,
          effect: true
        }
      }
    }
  },
  Step: {
    "editor": {
      text: 'Step',
      order: 37,
      groupOrder: navGroupOrder,
      group: navGroup,
      showInTree: false,
      moving({ toEditor, type2 }) {
        return toEditor &&
          (toEditor.name == 'Step' || (toEditor.name == 'Steps' && type2 == 'in'));
      },
      attrs: {
        status: {
          order: 1,
          type: 'select',
          value: "process",
          datas: ["wait", "process", "finish", "error"]
        },
        'title:title,content:desc,icon': {
          order: 5,
          effect: true
        }
      }
    }
  },
  Drawer: {
    transfer: _newEditingTransfer({ type: 'div' }),
    "editor": {
      text: 'Drawer 抽屉',
      order: 38,
      groupOrder: layoutGroupOrder,
      group: layoutGroup,
      icon: iconPre + 'md-list',
      container: true,
      attrs: {
        'title,width': {
          groupOrder: 1,
          order: 0
        },
        'transfer,mask,draggable': {
          order: 3,
          type: 'boolean'
        },
        placement: {
          order: 8,
          type: 'select',
          value: "right",
          datas: ["left", "right"]
        },
        'on-close,on-visible-change,on-resize-width': { order: 30, event: true }
      }
    }
  },
  Breadcrumb: {
    "editor": {
      text: 'Breadcrumb 面包屑',
      order: 39,
      groupOrder: navGroupOrder,
      group: navGroup,
      icon: iconPre + 'ios-arrow-forward',
      container: true,
      transferAttr({ render, editing }) {
        if (editing) {
          if (_.size(render.children) == 0) {
            render.children = [{
              type: 'BreadcrumbItem'
            }, {
              type: 'BreadcrumbItem'
            }];
          }
        }
      },
      attrs: {
        separator: {
          order: 0
        }
      }
    }
  },
  BreadcrumbItem: {
    "editor": {
      text: 'BreadcrumbItem',
      order: 40,
      groupOrder: navGroupOrder,
      group: navGroup,
      icon: iconPre + 'ios-arrow-forward',
      container: true,
      showInTree: false,
      inline: true,
      moving({ toEditor, type2 }) {
        return toEditor &&
          ((toEditor.name == 'BreadcrumbItem' && type2 != 'in') || (toEditor.name == 'Breadcrumb' && type2 == 'in'));
      },
      transferAttr({ render, editing }) {
        if (editing) {
          if (!render.children) {
            render.children = [{
              type: 'uieditor-text'
            }];
          }
        }
      },
      attrs: {
        separator: {
          order: 0
        }
      }
    }
  },
  Modal: {
    transfer: _newEditingTransfer({ type: 'div' }),
    "editor": {
      text: 'Modal 对话框',
      order: 41,
      groupOrder: viewGroupOrder,
      group: viewGroup,
      icon: iconPre + 'md-browsers',
      container: true,
      attrs: {
        'title,width,z-index,ok-text,cancel-text': {
          order: 1
        },
        'loading,transfer,mask,closable:true,fullscreen,draggable,footer-hide': {
          order: 8,
          type: 'boolean',
        },
        'on-ok,on-cancel,on-visible-change': { order: 30, event: true }
      }
    }
  },
  Badge: {
    "editor": {
      order: 42,
      groupOrder: viewGroupOrder,
      group: viewGroup,
      icon: iconPre + 'md-square',
      container: true,
      text: 'Badge 徽标数',
      inline: true,
      attrs: {
        text: {
          effect: true,
          order: 0
        },
        count: {
          effect: true,
          bind: true, enabledBind: false,
          order: 1
        },
        'overflow-count,offset': {
          order: 2
        },
        type: {
          order: 8,
          type: 'select',
          datas: ["success", "primary", "normal", "error", "warning", "info"]
        },
        status: {
          order: 5,
          type: 'select',
          datas: ["success", "processing", "default", "error", "warning"]
        },
        'dot,show-zero': {
          order: 6,
          type: 'boolean'
        }
      }
    }
  },
  Progress: {
    transfer: _newEditingTransfer({ props: { ':percent': '30' } }),
    "editor": {
      text: 'Progress 进度条',
      order: 43,
      groupOrder: viewGroupOrder,
      group: viewGroup,
      icon: iconPre + 'ios-thermometer-outline',
      attrs: {
        'percent,stroke-width,stroke-color,success-percent': {
          bind: true,
          enabledBind: false,
          order: 0
        },
        status: {
          order: 5,
          type: 'select',
          datas: ["success", "normal", "wrong", "active"]
        },
        'hide-info,vertical': {
          order: 6,
          type: 'boolean'
        }
      }
    }
  },
  Upload: {
    transfer: _newEditingTransfer({ type: 'div' }),
    "editor": {
      text: 'Upload 上传',
      order: 44,
      groupOrder: formGroupOrder,
      group: formGroup,
      icon: iconPre + 'ios-cloud-upload-outline',
      container: true,
      inline: true,
      disabledAttr: true,
      attrs: {
        'action,headers,data,name,accept,format,max-size,before-upload,default-file-list': {
          order: 0
        },
        'style,class': { show: false, effect: false },
        type: {
          order: 10,
          type: 'select',
          datas: ["select", "drag"]
        },
        'multiple,paste,with-credentials,show-upload-list': {
          order: 16,
          type: 'boolean'
        },
        'on-progress,on-success,on-error,on-preview,on-remove,on-format-error,on-exceeded-size': {
          bind: true,
          enabledBind: false,
          order: 30
        }
      }
    }
  },
  Split: {
    transfer: _newEditingTransfer({
      children: [{
        props: { 'class': "control-left" }
      }]
    }),
    "editor": {
      order: 45,
      groupOrder: layoutGroupOrder,
      group: layoutGroup,
      text: 'Split 面板分割',
      container: true,
      controlLeft: false,
      icon: iconPre + 'ios-pause',
      contenting() { return false; },
      transferAttr({ render, attrs, editing }) {
        if (editing) {
          if (_.size(render.children) == 0) {
            const child = {
              type: 'div',
              props: {
                slot: 'left',
                style: 'height:100%;'
              },
              children: [{
                type: 'uieditor-div',
                props: {
                  style: 'height:100%;overflow: hidden;',
                  [UECanNotMoveChildProps]: true,
                  [UECanNotRemoveChildProps]: true,
                  [UECanNotCopyChildProps]: true,
                  [UECanNotMoveInProps]: true,
                  [UECanNotMoveOutProps]: true
                },
                children: [{
                  type: 'uieditor-div',
                  props: {
                    style: 'height:100%;overflow: auto;'
                  }
                }]
              }]
            };
            render.children = [
              _.cloneDeep(child),
              _.cloneDeep(child)
            ];
          }
          const { mode } = attrs;
          const modeValue = mode.value;
          _.first(render.children)['props'].slot = modeValue == 'vertical' ? 'top' : 'left'
          _.last(render.children)['props'].slot = modeValue == 'vertical' ? 'bottom' : 'right'
        }
      },
      attrs: {
        mode: {
          order: 0,
          type: 'select',
          effect: true,
          datas: ['horizontal', 'vertical']
        },
        'min,max': {
          order: 1,
          type: 'boolean'
        },
        style: { value: 'min-height:100px' },
        'on-move-start,on-moving,on-move-end': { event: true, order: 30 }
      }
    }
  },
  Collapse: {
    "editor": {
      order: 46,
      groupOrder: layoutGroupOrder,
      group: layoutGroup,
      text: 'Collapse 折叠面板',
      icon: iconPre + 'md-options',
      container: true,
      json: {
        props: {
          [UECanNotMoveInProps]: true,
          [UECanNotMoveOutProps]: true
        }
      },
      toolbar({ render, service }) {
        return [
          {
            title: "添加",
            icon: "layui-icon layui-icon-addition",
            click() {
              const name = "pane" + UEHelper.makeAutoId();
              service.setRenderTemp(render.editorId, 'collapse_cur', name);
              service.addByJson(
                { "type": "Panel", "props": { "name": name } },
                render.editorId,
                "in"
              ).then(function () {
                service.setCurrent(render.editorId);
              });
            },
          },
        ];
      },
      attrs: {
        'accordion,simple': {
          order: 2,
          type: 'boolean',
          bind: true,
        },
        'on-change': { event: true, order: 30 }
      },
      transferAttr({ render, service, editing }) {
        //必须保留一个TabPane
        if (!render.children || render.children.length == 0) {
          render.children = [{ type: 'Panel' }];
        }

        const props = render.props;
        if (editing) {
          //编辑时，保留当前tab页
          const id = render.editorId;
          const temp = service.getRenderTemp(id, 'collapse_cur');

          props[':value'] = JSON.stringify(temp || []);
          props[':animated'] = 'false';
          props['@on-change'] = `$service.setRenderTemp('${id}', 'collapse_cur', $event)`;

        } else {
          delete props[':value'];
          delete props[':animated'];
          delete props['@on-change'];
        }

      }
    }
  },
  Panel: {
    "editor": {
      text: 'Panel',
      order: 47,
      groupOrder: layoutGroupOrder,
      group: layoutGroup,
      showInTree: false,
      container: true,
      controlLeft: false,
      coping({ render, parent, service }) {
        const name = "pane" + UEHelper.makeAutoId();
        let pId = parent?.editorId;
        service.setRenderTemp(pId, 'collapse_cur', name);
        render.props = _.assign({}, render.props, {
          name
        });
        return true;
      },
      transferAttr({ render, editing }) {
        if (editing) {
          if (_.size(render.children) == 0) {
            render.children = [{
              type: 'uieditor-span',
              children: [
                {
                  type: 'uieditor-text',
                  props: { text: '标题' }
                }
              ]
            }, {
              type: 'p',
              props: { slot: 'content' },
              children: [{
                type: 'uieditor-div',
                props: {
                  [UECanNotMoveInProps]: true
                },
                children: [{
                  type: 'uieditor-div',
                  props: {
                    [UECanNotRemoveProps]: true,
                    [UECanNotCopyProps]: true
                  },
                  children: [{
                    type: 'uieditor-text',
                    props: { text: '内容' }
                  }]
                }]
              }]
            }]
          }
        }
      },
      attrs: {
        'name': {
          order: 1,
          value: 'pane1',
          effect: true
        },
        'hide-arrow': {
          order: 2,
          type: 'boolean'
        }
      }
    }
  },
  Spin: {
    transfer: _newEditingTransfer({ type: 'div' }),
    editor: {
      text: 'Spin 加载中',
      order: 48,
      groupOrder: viewGroupOrder,
      group: viewGroup,
      icon: iconPre + 'ios-ionic-outline',
      container: true,
      attrs: {
        'size': {
          desc: 'Spin尺寸',
          order: 0,
          type: 'select',
          datas: ['large', 'small'],
          effect: true
        },
        'fix': {
          desc: '需要父级有relative或absolute',
          order: 0,
          type: 'boolean'
        }
      }
    }
  },
  Page: {
    "editor": {
      text: 'Page 分页',
      order: 49,
      groupOrder: navGroupOrder,
      group: navGroup,
      icon: iconPre + 'ios-more',
      container: false,
      attrs: {
        'current': {
          desc: '当前页码',
          order: 0,
          value: 1,
          effect: true,
          type: 'number'
        },
        'total': {
          desc: '数据总数',
          order: 1,
          value: 50,
          effect: true,
          type: 'number'
        },
        'page-size': {
          desc: '每页条数',
          order: 0,
          value: 10,
          type: 'number',
          editorBind: true
        },
        'page-size-opts': {
          desc: '每页条数切换的配置',
          order: 0,
          value: '[10,20,30,40]',
          bind: true,
          enabledBind: false,
          editorBind: true
        },
        'simple': {
          desc: '简洁版',
          order: 0,
          type: 'boolean',
          editorBind: true
        },
        'show-total': {
          desc: '显示总数',
          order: 0,
          type: 'boolean',
          editorBind: true
        },
        'show-elevator': {
          desc: '显示电梯，可以快速切换到某一页',
          order: 0,
          type: 'boolean'
        },
        'show-sizer': {
          desc: '显示分页，用来改变page-size',
          order: 0,
          type: 'boolean',
          editorBind: true
        },
        'class-name': {
          desc: '自定义 class 名称',
          order: 0
        },
        'styles': {
          desc: '自定义 style 样式',
          order: 0
        },
        'disabled': {
          desc: '是否禁用',
          order: 0,
          type: 'boolean',
          value: 'false',
          editorBind: true
        },
        'on-change': {
          desc: '页码改变的回调',
          order: 30,
          event: true
        },
        'on-page-size-change': {
          desc: '切换每页条数时的回调',
          order: 31,
          event: true
        }
      }
    }
  },
  Table: {
    "editor": {
      text: 'Table 表格',
      order: 50,
      groupOrder: formGroupOrder,
      group: formGroup,
      icon: iconPre + 'ios-calculator',
      container: true,
      attrs: _newTableAttrs(),
    }
  },
  'iview-uieditor-table': {
    transfer: _newEditingTransfer({
      props: { editing: 'true' }
    }),
    "editor": {
      text: 'Table 插槽版',
      order: 50,
      groupOrder: formGroupOrder,
      group: formGroup,
      icon: iconPre + 'ios-calculator',
      container: true,
      toolbar({ render, service }) {
        return [
          {
            title: "添加插槽",
            icon: "layui-icon layui-icon-addition",
            click() {
              service.addByJson({
                "type": "template",
                "props": {
                  "slot": "name",
                  "slot-scope": "{ row, index }"
                },
                "children": [
                  {
                    "children": [
                      {
                        "type": "uieditor-text",
                        "props": {
                          ":text": "row.name"
                        }
                      }
                    ],
                    "type": "uieditor-a"
                  }
                ]
              },
                render.editorId,
                "in"
              ).then(function () {
                service.setCurrent(render.editorId);
              });

            },
          }
        ];
      },
      attrs: _newTableAttrs(),
    }
  },
  Rate: {
    "editor": {
      text: 'Rate 评分',
      order: 51,
      groupOrder: formGroupOrder,
      group: formGroup,
      icon: iconPre + 'md-star',
      attrs: {
        'count': {
          text: 'star 总数',
          order: 1,
          value: 5,
          demoValue: 5,
          effect: true,
          bind: true,
          editorBind: true
        },
        'value': {
          text: '当前 star 数',
          order: 2,
          value: 2,
          demoValue: 2,
          effect: true,
          bind: true,
          editorBind: true
        },
        'allow-half': {
          text: '是否允许半选',
          order: 3,
          type: 'boolean',
        },
        'disabled': {
          text: '是否只读',
          order: 4,
          type: 'boolean'
        },
        'show-text': {
          text: '是否显示提示文字',
          order: 5,
          type: 'boolean-only',
          effect: true
        },
        'clearable': {
          text: '是否可以取消选择',
          order: 6,
          type: 'boolean'
        },
        'character': {
          text: '自定义字符',
          order: 7,
          bind: false
        },
        'icon': {
          text: '使用图标',
          order: 8,
          effect: true
        },
        'custom-icon': {
          text: '使用自定义图标',
          order: 9,
          effect: true
        },
        'on-change': {
          desc: '	评分改变时触发',
          text: '',
          order: 30,
          event: true
        }
      }
    }
  }
});
